﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Drawing;
using Google.API.Translate;
using System.IO;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Configuration;


namespace Granslator
{
    public partial class frmMain : Form
    {

        public frmMain()
        {
            InitializeComponent();
        }

        #region Properties

        public bool RunByWindows
        {
            get;
            set;
        }

        public int SourceLanguage
        {
            get
            {
                return Properties.Settings.Default.SourceLanguage;
            }
            set
            {
                Properties.Settings.Default.SourceLanguage = value;
                cboFrom.SelectedIndex = value;
            }
        }

        public int TargetLanguage
        {
            get
            {
                return Properties.Settings.Default.TargetLanguage;
            }
            set
            {
                Properties.Settings.Default.TargetLanguage = value;
                cboTo.SelectedIndex = value;
            }
        }

        public Font EditorFont
        {
            get
            {
                return Properties.Settings.Default.EditorFont;
            }
            set
            {
                txtFrom.Font = value;
                txtTo.Font = value;
                Properties.Settings.Default.EditorFont = value;
            }
        }

        public bool HideWhenMinimize
        {
            get
            {
                return Properties.Settings.Default.HideWhenMinimize;
            }
            set
            {
                Properties.Settings.Default.HideWhenMinimize = value;
            }
        }

        public bool RunWithWindows
        {
            get
            {
                return Properties.Settings.Default.RunWithWindows;
            }
            set
            {
                Properties.Settings.Default.RunWithWindows = value;
            }
        }

        public bool Remember
        {
            get;
            set;
        }

        #endregion

        #region WIN32 API

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static public extern IntPtr GetForegroundWindow();

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct STRINGBUFFER
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string szText;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);

        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_CLOSE = 0xF060;

        public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool RegisterHotKey(IntPtr hWnd, // handle to window    
            int id,            // hot key identifier    
            KeyModifiers fsModifiers,  // key-modifier options    
            Keys vk            // virtual-key code    
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool UnregisterHotKey(IntPtr hWnd,  // handle to window    
            int id      // hot key identifier    
            );

        [Flags()]
        public enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            Windows = 8
        }

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        [DllImport("user32.dll")]
        static extern bool AttachThreadInput(uint idAttach, uint idAttachTo,

        bool fAttach);

        [DllImport("user32.dll")]
        static extern IntPtr GetFocus();

        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

        // second overload of SendMessage

        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);

        const uint WM_GETTEXT = 0x0D;
        const uint WM_GETTEXTLENGTH = 0x0E;
        const uint EM_GETSEL = 0xB0;

        private string GetSelText()
        {
            IntPtr hWnd = GetForegroundWindow();
            uint processId;
            uint activeThreadId = GetWindowThreadProcessId(hWnd, out processId);
            uint currentThreadId = GetCurrentThreadId();
            AttachThreadInput(activeThreadId, currentThreadId, true);
            IntPtr focusedHandle = GetFocus();
            AttachThreadInput(activeThreadId, currentThreadId, false);
            int len = SendMessage(focusedHandle, WM_GETTEXTLENGTH, 0, null);
            StringBuilder sb = new StringBuilder(len);
            int numChars = SendMessage(focusedHandle, WM_GETTEXT, len + 1, sb);
            int start, next;
            SendMessage(focusedHandle, EM_GETSEL, out start, out next);
            string selectedText = sb.ToString().Substring(start, next - start);
            MessageBox.Show(selectedText);
            return selectedText;
        }

        protected override void WndProc(ref Message m)
        {
            const int WM_HOTKEY = 0x0312;

            switch (m.Msg)
            {
                case WM_HOTKEY:
                    this.Show();
                    WindowState = FormWindowState.Normal;
                    break;
            }
            base.WndProc(ref m);
        }

        #endregion


        /// <summary>
        /// Check if user connected to Internet for Online Translation or Not
        /// </summary>
        /// <returns></returns>
        private bool CheckForInternetConnection()
        {
            try
            {
                System.Net.IPHostEntry ipnet = System.Net.Dns.GetHostEntry("www.google.com");
                lblOnline.Visible = true;
                lblOffline.Visible = false;
                TrayIcon.Text = "Granslator - Your are Online";
                return true; // host is reachable
            }
            catch
            {
                lblOnline.Visible = false;
                lblOffline.Visible = true;
                TrayIcon.Text = "Granslator - Your are Offline";
                return false; // host is NOT reachable
            } 
        }


        /// <summary>
        /// Initialize controls and Register a Global Hotkey for application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">EventArgs</param>
        private void Form1_Load(object sender, EventArgs e)
        {
            RunWithWindows = AutoStart.IsAutoStartEnabled("Granslator", Application.ExecutablePath + "-hide");
            cboFrom.SelectedIndex = SourceLanguage;
            cboTo.SelectedIndex = TargetLanguage;
            txtFrom.Font = EditorFont;
            txtTo.Font = EditorFont;
            Remember = Properties.Settings.Default.Remember;
            bool success = RegisterHotKey(Handle, 100, KeyModifiers.Control | KeyModifiers.Shift, Keys.G);
            lblSaveAs.Enabled = false;
            lblCopyToClipboard.Enabled = false;
            CheckForInternetConnection();
        }

        /// <summary>
        /// Translate input text using translate.google.com
        /// </summary>
        /// <param name="from">Source Language</param>
        /// <param name="to">Target Language</param>
        private void TranslateByGoogle(int from, int to)
        {
            Language LanguageFrom = Language.Unknown;
            Language LanguageTo = Language.Unknown;

            switch (from)
            {
                case 0: LanguageFrom = Language.Arabic;
                    break;
                case 1: LanguageFrom = Language.Bulgarian;
                    break;
                case 2: LanguageFrom = Language.Chinese;
                    break;
                case 3: LanguageFrom = Language.Croatian;
                    break;
                case 4: LanguageFrom = Language.Czech;
                    break;
                case 5: LanguageFrom = Language.Danish;
                    break;
                case 6: LanguageFrom = Language.Dutch;
                    break;
                case 7: LanguageFrom = Language.English;
                    break;
                case 8: LanguageFrom = Language.Finnish;
                    break;
                case 9: LanguageFrom = Language.French;
                    break;
                case 10: LanguageFrom = Language.German;
                    break;
                case 11: LanguageFrom = Language.Greek;
                    break;
                case 12: LanguageFrom = Language.Hindi;
                    break;
                case 13: LanguageFrom = Language.Italian;
                    break;
                case 14: LanguageFrom = Language.Japanese;
                    break;
                case 15: LanguageFrom = Language.Korean;
                    break;
                case 16: LanguageFrom = Language.Norwegian;
                    break;
                case 17: LanguageFrom = Language.Persian;
                    break;
                case 18: LanguageFrom = Language.Polish;
                    break;
                case 19: LanguageFrom = Language.Portuguese;
                    break;
                case 20: LanguageFrom = Language.Romanian;
                    break;
                case 21: LanguageFrom = Language.Russian;
                    break;
                case 22: LanguageFrom = Language.Spanish;
                    break;
                case 23: LanguageFrom = Language.Swedish;
                    break;
            }

            switch (to)
            {
                case 0: LanguageTo = Language.Arabic;
                    break;
                case 1: LanguageTo = Language.Bulgarian;
                    break;
                case 2: LanguageTo = Language.Chinese;
                    break;
                case 3: LanguageTo = Language.Croatian;
                    break;
                case 4: LanguageTo = Language.Czech;
                    break;
                case 5: LanguageTo = Language.Danish;
                    break;
                case 6: LanguageTo = Language.Dutch;
                    break;
                case 7: LanguageTo = Language.English;
                    break;
                case 8: LanguageTo = Language.Finnish;
                    break;
                case 9: LanguageTo = Language.French;
                    break;
                case 10: LanguageTo = Language.German;
                    break;
                case 11: LanguageTo = Language.Greek;
                    break;
                case 12: LanguageTo = Language.Hindi;
                    break;
                case 13: LanguageTo = Language.Italian;
                    break;
                case 14: LanguageTo = Language.Japanese;
                    break;
                case 15: LanguageTo = Language.Korean;
                    break;
                case 16: LanguageTo = Language.Norwegian;
                    break;
                case 17: LanguageTo = Language.Persian;
                    break;
                case 18: LanguageTo = Language.Polish;
                    break;
                case 19: LanguageTo = Language.Portuguese;
                    break;
                case 20: LanguageTo = Language.Romanian;
                    break;
                case 21: LanguageTo = Language.Russian;
                    break;
                case 22: LanguageTo = Language.Spanish;
                    break;
                case 23: LanguageTo = Language.Swedish;
                    break;
            }

            try
            {
                txtTo.Text = Translator.Translate(txtFrom.Text, LanguageFrom, LanguageTo); 
            }
            catch ( TranslateException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        /// <summary>
        /// Swap source and target Languages
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lblSwap_Click(object sender, EventArgs e)
        {
            int i = cboFrom.SelectedIndex;
            cboFrom.SelectedIndex = cboTo.SelectedIndex;
            cboTo.SelectedIndex = i;
        }


        private void txtFrom_TextChanged(object sender, EventArgs e)
        {
            int len = txtFrom.Text.Length;
            statusLabel.Text = len.ToString() + " character(s)";
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnregisterHotKey(Handle, 100);
        }

        private void btnTranslate_Click(object sender, EventArgs e)
        {
            if (txtFrom.Text == string.Empty)
            {
                MessageBox.Show("Enter something first.");
                txtFrom.Focus();
                return;
            }
            this.Enabled = false;
            TranslateByGoogle(cboFrom.SelectedIndex, cboTo.SelectedIndex);
            this.Enabled = true;
        }

        #region MouseMove and MouseLeave Event Handlers

        private void lblOpen_MouseMove(object sender, MouseEventArgs e)
        {
            lblOpen.BackColor = SystemColors.Highlight;
            lblOpen.ForeColor = Color.White;
        }

        private void lblOpen_MouseLeave(object sender, EventArgs e)
        {
            lblOpen.BackColor = SystemColors.ButtonFace;
            lblOpen.ForeColor = Color.Blue;
        }

        private void lblPaste_MouseMove(object sender, MouseEventArgs e)
        {
            lblPaste.BackColor = SystemColors.Highlight;
            lblPaste.ForeColor = Color.White;
        }

        private void lblPaste_MouseLeave(object sender, EventArgs e)
        {
            lblPaste.BackColor = SystemColors.ButtonFace;
            lblPaste.ForeColor = Color.Blue;
        }

        private void lblSaveAs_MouseMove(object sender, MouseEventArgs e)
        {
            lblSaveAs.BackColor = SystemColors.Highlight;
            lblSaveAs.ForeColor = Color.White;
        }

        private void lblSaveAs_MouseLeave(object sender, EventArgs e)
        {
            lblSaveAs.BackColor = SystemColors.ButtonFace;
            lblSaveAs.ForeColor = Color.Blue;
        }

        private void lblCopyToClipboard_MouseMove(object sender, MouseEventArgs e)
        {
            lblCopyToClipboard.BackColor = SystemColors.Highlight;
            lblCopyToClipboard.ForeColor = Color.White;
        }

        private void lblCopyToClipboard_MouseLeave(object sender, EventArgs e)
        {
            lblCopyToClipboard.BackColor = SystemColors.ButtonFace;
            lblCopyToClipboard.ForeColor = Color.Blue;
        }

        private void lblAbout_MouseMove(object sender, MouseEventArgs e)
        {
            lblAbout.BackColor = SystemColors.Highlight;
            lblAbout.ForeColor = Color.White;
        }

        private void lblAbout_MouseLeave(object sender, EventArgs e)
        {
            lblAbout.BackColor = SystemColors.ButtonFace;
            lblAbout.ForeColor = Color.Blue;
        }

        private void lblFont_MouseMove(object sender, MouseEventArgs e)
        {
            lblFont.BackColor = SystemColors.Highlight;
            lblFont.ForeColor = Color.White;
        }

        private void lblFont_MouseLeave(object sender, EventArgs e)
        {
            lblFont.BackColor = SystemColors.ButtonFace;
            lblFont.ForeColor = Color.Blue;
        }

        private void lblWizard_MouseMove(object sender, MouseEventArgs e)
        {
            lblWizard.BackColor = SystemColors.Highlight;
            lblWizard.ForeColor = Color.White;
        }

        private void lblWizard_MouseLeave(object sender, EventArgs e)
        {
            lblWizard.BackColor = SystemColors.ButtonFace;
            lblWizard.ForeColor = Color.Blue;
        }


        #endregion

        private void lblCopyToClipboard_Click(object sender, EventArgs e)
        {
            txtTo.SelectAll();
            txtTo.Copy();
        }

        private void txtTo_TextChanged(object sender, EventArgs e)
        {
            if (txtTo.Text != string.Empty)
            {
                lblSaveAs.Enabled = true;
                lblCopyToClipboard.Enabled = true;
            }
            else
            {
                lblSaveAs.Enabled = false;
                lblCopyToClipboard.Enabled = false;
            }
        }

        private void lblPaste_Click(object sender, EventArgs e)
        {
            txtFrom.Text = Clipboard.GetText();
        }

        private void lblOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog Opendlg = new OpenFileDialog();
            Opendlg.DefaultExt = "txt";
            Opendlg.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
            if (Opendlg.ShowDialog() == DialogResult.OK)
            {
                StreamReader reader = File.OpenText(Opendlg.FileName);
                txtFrom.Text = reader.ReadToEnd();
            }
            Opendlg.Dispose();
        }

        private void lblSaveAs_Click(object sender, EventArgs e)
        {
            SaveFileDialog Savedlg = new SaveFileDialog();
            Savedlg.DefaultExt = "txt";
            Savedlg.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
            if (Savedlg.ShowDialog() == DialogResult.OK)
            {
                StreamWriter writer = File.CreateText(Savedlg.FileName);
                writer.Write(txtTo.Text);
                writer.Flush();
                writer.Close();
            }
            Savedlg.Dispose();
        }

        private void lblDetect_Click(object sender, EventArgs e)
        {
            if (txtFrom.Text == string.Empty)
            {
                MessageBox.Show("Enter something first!");
                return;
            }
            bool reliable = false;
            double d = 0;
            Language l = Language.Unknown;
            this.Enabled = false;
            try
            {
                l = Translator.Detect(txtFrom.Text, out reliable, out d);
                NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
                nfi.NumberGroupSeparator = " ";
                if (MessageBox.Show("Detected as " + l.ToString() + " , with a score of " +
                    d.ToString("P", nfi) + ". Do you want to select this language as the" +
                        " From language?",
                        "Detection", MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    switch (l)
                    {
                        case Language.Arabic: cboFrom.SelectedIndex = 0;
                            break;
                        case Language.Bulgarian: cboFrom.SelectedIndex = 1;
                            break;
                        case Language.Chinese: cboFrom.SelectedIndex = 2;
                            break;
                        case Language.Croatian: cboFrom.SelectedIndex = 3; ;
                            break;
                        case Language.Czech: cboFrom.SelectedIndex = 4; ;
                            break;
                        case Language.Danish: cboFrom.SelectedIndex = 5;
                            break;
                        case Language.Dutch: cboFrom.SelectedIndex = 6;
                            break;
                        case Language.English: cboFrom.SelectedIndex = 7;
                            break;
                        case Language.Finnish: cboFrom.SelectedIndex = 8;
                            break;
                        case Language.French: cboFrom.SelectedIndex = 9;
                            break;
                        case Language.German: cboFrom.SelectedIndex = 10;
                            break;
                        case Language.Greek: cboFrom.SelectedIndex = 11;
                            break;
                        case Language.Hindi: cboFrom.SelectedIndex = 12;
                            break;
                        case Language.Italian: cboFrom.SelectedIndex = 13;
                            break;
                        case Language.Japanese: cboFrom.SelectedIndex = 14;
                            break;
                        case Language.Korean: cboFrom.SelectedIndex = 15;
                            break;
                        case Language.Norwegian: cboFrom.SelectedIndex = 16;
                            break;
                        case Language.Persian: cboFrom.SelectedIndex = 17;
                            break;
                        case Language.Polish: cboFrom.SelectedIndex = 18;
                            break;
                        case Language.Portuguese: cboFrom.SelectedIndex = 19;
                            break;
                        case Language.Romanian: cboFrom.SelectedIndex = 20;
                            break;
                        case Language.Russian: cboFrom.SelectedIndex = 21;
                            break;
                        case Language.Spanish: cboFrom.SelectedIndex = 22;
                            break;
                        case Language.Swedish: cboFrom.SelectedIndex = 23;
                            break;
                    }
                }
                this.Enabled = true;
            }
            catch (TranslateException ex)
            {
                MessageBox.Show("Language detection faild. Check if you are connected to internet or not, then try again.",
                            "Language Detection", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Enabled = true;
                return;
            }
        }

        private void tmrCheckInternetState_Tick(object sender, EventArgs e)
        {
            CheckForInternetConnection();
        }

        private void lblAbout_Click(object sender, EventArgs e)
        {
            frmAbout about = new frmAbout();
            try
            {
                about.ShowDialog();
            }
            finally
            {
                about.Dispose();
            }
        }

        private void Settings_Click(object sender, EventArgs e)
        {
            frmSettings SettingsForm = new frmSettings();

            SettingsForm.Properties.DefaultSourceLanguage =
                (GranslatorSettings.SupportedLanguages)Properties.Settings.Default.SourceLanguage;
            SettingsForm.Properties.DefaultTargetLanguage =
                (GranslatorSettings.SupportedLanguages)Properties.Settings.Default.TargetLanguage;
            SettingsForm.Properties.EditorFont = this.EditorFont;
            SettingsForm.Properties.HideWhenMinimize = this.HideWhenMinimize;
            SettingsForm.Properties.RunWithWindows = this.RunWithWindows;
            SettingsForm.Properties.RememberLanguages = this.Remember;

            if (SettingsForm.ShowDialog() == DialogResult.OK)
            {
                this.EditorFont = SettingsForm.Properties.EditorFont;
                this.HideWhenMinimize = SettingsForm.Properties.HideWhenMinimize;
                this.RunWithWindows = SettingsForm.Properties.RunWithWindows;
                Properties.Settings.Default.Remember = SettingsForm.Properties.RememberLanguages;
                Remember = SettingsForm.Properties.RememberLanguages;
                if (!SettingsForm.Properties.RememberLanguages)
                {
                    Properties.Settings.Default.SourceLanguage =
                        (int)SettingsForm.Properties.DefaultSourceLanguage;
                    Properties.Settings.Default.TargetLanguage =
                        (int)SettingsForm.Properties.DefaultTargetLanguage;
                }
                if (SettingsForm.Properties.RunWithWindows)
                    AutoStart.SetAutoStart("Granslator", Application.ExecutablePath + "-hide");
                else
                    if (AutoStart.IsAutoStartEnabled("Granslator", Application.ExecutablePath + "-hide"))
                        AutoStart.UnSetAutoStart("Granslator");
                
                Properties.Settings.Default.Save();
            }
        }

        private void mnuShowHide_Click(object sender, EventArgs e)
        {
            if (Visible)
            {
                Hide();
                return;
            }
            Show();
            WindowState = FormWindowState.Normal;
        }

        private void frmMain_SizeChanged(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState)
                if (HideWhenMinimize)
                    Hide();
        }

        private void TrayIcon_DoubleClick(object sender, EventArgs e)
        {
            this.Show();
            WindowState = FormWindowState.Normal;
        }

        private void mnuExit_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Do you realy want to Exit?", "Granslator", MessageBoxButtons.YesNo,
                MessageBoxIcon.Question) == DialogResult.Yes)
            {
                Application.Exit();
            }
        }

        private void txtFrom_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.A)
            {
                txtFrom.SelectAll();
            }
        }

        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (Remember)
            {
                Properties.Settings.Default.SourceLanguage = cboFrom.SelectedIndex;
                Properties.Settings.Default.TargetLanguage = cboTo.SelectedIndex;
                Properties.Settings.Default.Save();
            }
        }

        private void frmMain_VisibleChanged(object sender, EventArgs e)
        {

        }

        private void frmMain_Activated(object sender, EventArgs e)
        {
            if (RunByWindows)
                Hide();
            RunByWindows = false;
        }

        private void frmMain_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized) return;
            txtFrom.Width = this.Width / 2 - 20;
            txtTo.Width = this.Width / 2 - 20;
        }

        private void lblWizard_Click(object sender, EventArgs e)
        {
            frmWizard Wizard = new frmWizard();
            Wizard.SourceText = txtFrom.Text;
            Wizard.SourceLanguage = cboFrom.SelectedIndex;
            Wizard.TargetLanuage = cboTo.SelectedIndex;
            try
            {
                Wizard.ShowDialog();
                if (Wizard.ReplcaeResultsInMainForm)
                    txtTo.Text = Wizard.Result;
            }
            finally
            {
                Wizard.Dispose();
            }
        }
    }
}
